/**
 * Copyright 2008-2009 HAN.BIFANG
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
package han.bashe.business.servicequery;

import han.bashe.business.pipeline.Handler;
import han.bashe.business.pipeline.PipelineContext;
import han.bashe.common.config.Config;
import han.bashe.common.entity.BasheEntityConstants;
import han.bashe.common.entity.BifangEntityConstants;
import han.bashe.common.exception.BasheErrorCode;
import han.bashe.common.exception.BasheException;
import han.bashe.common.message.NormalizedMessage;
import han.bashe.common.message.RequestHelper;
import han.bashe.common.schema.MappingServiceInfoWrapper;
import han.bashe.common.schema.ServiceInfoWrapper;

import java.util.HashMap;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import v1.query.web.bifang.han.QosDocument.Qos;
import v1.query.web.bifang.han.WebServicesMethodDocument.WebServicesMethod;

/**
 * @Author Kent
 */
public class ServiceInfoQueryHandler extends Handler {
	private static Log logger = LogFactory
			.getLog(ServiceInfoQueryHandler.class);

	@Override
	public void postProcess(PipelineContext ctx) {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean preProcess(PipelineContext ctx) {
		if (ctx.hasError())
			return false;
		return true;
	}

	@Override
	public void process(PipelineContext ctx) {
		logger.info("ServiceInfoQueryHandler process......");
		try {
			NormalizedMessage req = ctx.getRequest();

			RequestHelper rh = new RequestHelper(req);

			String serviceCode = rh.getServiceCode();
			if (serviceCode == null) {
				throw new BasheException(BasheErrorCode.MISS_HEADER_ERROR,
						"missing requied header SOA_ServiceCode");
			}

			Object ser = CacheWrapper.getService(serviceCode);

			if (ser == null) {
				throw new BasheException(
						BasheErrorCode.REQUESTED_SERVICE_NOT_EXIST_ERROR,
						"service [" + serviceCode + "] not exists");
			}
			if (ser instanceof ServiceInfoWrapper) {
				ServiceInfoWrapper tmp = (ServiceInfoWrapper) ser;
				if (tmp.getService().getStatus().equals(
						BifangEntityConstants.SERVICE_STATUS_UNPUBLISHED)) {
					throw new BasheException(
							BasheErrorCode.REQUESTED_SERVICE_NOT_PUBLISHED_ERROR,
							"serivce [" + serviceCode + "] not published");
				}
				String version = rh.getServiceVersion();
				if (version == null) {
					if (tmp.getDefaultVersion() == null) {
						throw new BasheException(
								BasheErrorCode.SERVICE_VERSION_ERROR,
								"default version of service ["
										+ serviceCode
										+ "] isn't set. you must set a version in request header");
					}
					if (tmp.getDefaultVersion().getStatus().equals(
							BifangEntityConstants.SERVICE_STATUS_UNPUBLISHED)) {
						throw new BasheException(
								BasheErrorCode.REQUESTED_VERSION_NOT_PUBLISHED_ERROR,
								"default version of service [" + serviceCode
										+ "] not published");
					}
					rh.setServiceVersion(tmp.getDefaultVersion().getVersion());
					version = tmp.getDefaultVersion().getVersion();
				} else {
					if (tmp.getVersion(version) == null) {
						throw new BasheException(
								BasheErrorCode.SERVICE_VERSION_ERROR,
								"no such version [" + version
										+ "] of service [" + serviceCode + "] ");
					}
					if (tmp.getVersion(version).getStatus().equals(
							BifangEntityConstants.SERVICE_STATUS_UNPUBLISHED)) {
						throw new BasheException(
								BasheErrorCode.REQUESTED_VERSION_NOT_PUBLISHED_ERROR,
								"version [" + version + "] of serivce ["
										+ serviceCode + "] not published");
					}
				}
				if (rh.getReplyServiceCode() != null) {
					Object ser1 = CacheWrapper.getService(rh
							.getReplyServiceCode().trim());

					if (ser1 == null) {
						throw new BasheException(
								BasheErrorCode.REQUESTED_SERVICE_NOT_EXIST_ERROR,
								"service [" + rh.getReplyServiceCode()
										+ "] not exists");
					}
					if (ser1 instanceof ServiceInfoWrapper) {
						ServiceInfoWrapper tmp1 = (ServiceInfoWrapper) ser;
						if (tmp1
								.getService()
								.getStatus()
								.equals(
										BifangEntityConstants.SERVICE_STATUS_UNPUBLISHED)) {
							throw new BasheException(
									BasheErrorCode.REQUESTED_SERVICE_NOT_PUBLISHED_ERROR,
									"serivce [" + rh.getReplyServiceCode()
											+ "] not published");
						}
						String version1 = rh.getReplyServiceVersion();
						if (version1 == null) {
							if (tmp1.getDefaultVersion() == null) {
								throw new BasheException(
										BasheErrorCode.SERVICE_VERSION_ERROR,
										"default version of service ["
												+ rh.getReplyServiceCode()
												+ "] isn't set. you must set a version in request header");
							}
							if (tmp1
									.getDefaultVersion()
									.getStatus()
									.equals(
											BifangEntityConstants.SERVICE_STATUS_UNPUBLISHED)) {
								throw new BasheException(
										BasheErrorCode.REQUESTED_VERSION_NOT_PUBLISHED_ERROR,
										"default version of service ["
												+ rh.getReplyServiceCode()
												+ "] not published");
							}
							// rh.setServiceVersion(tmp.getDefaultVersion().getVersion());
							// version = tmp.getDefaultVersion().getVersion();
						} else {
							if (tmp1.getVersion(version1) == null) {
								throw new BasheException(
										BasheErrorCode.SERVICE_VERSION_ERROR,
										"no such version [" + version1
												+ "] of service ["
												+ rh.getReplyServiceCode()
												+ "] ");
							}
							if (tmp1
									.getVersion(version1)
									.getStatus()
									.equals(
											BifangEntityConstants.SERVICE_STATUS_UNPUBLISHED)) {
								throw new BasheException(
										BasheErrorCode.REQUESTED_VERSION_NOT_PUBLISHED_ERROR,
										"version [" + version1
												+ "] of serivce ["
												+ rh.getReplyServiceCode()
												+ "] not published");
							}
						}
					}
				}

				ctx.setService(tmp);
				if (tmp.getService().getBusRelList().size() == 0) {
					// serivce has no bus relationship, this means any bus can
					// call it
					ctx.setBindingToThisBus(true);
				} else {
					for (String busId : tmp.getService().getBusRelList()) {
						if (busId.equals(Config.getCurrentBusId())) {
							ctx.setBindingToThisBus(true);
							break;
						}
					}
				}

				if (tmp.getVersion(version).getBindingType().equals(
						BifangEntityConstants.BINDING_WEB_SERVICES)) {
					boolean hasMethod = false;

					if (!rh.getOrginMsgType().equals(
							BasheEntityConstants.WS_TYPE)) {
						if (rh.getMethod() == null) {
							throw new BasheException(
									BasheErrorCode.MISS_HEADER_ERROR,
									"you must"
											+ "set SOA_Method header to call web services if you use"
											+ "http/soap/jms protocol");
						}
						List<WebServicesMethod> l = tmp.getVersion(version)
								.getBinding().getWebServicesBinding()
								.getWebServicesMethodList();

						for (WebServicesMethod m : l) {
							if (m.getMethodName().equals(rh.getMethod())) {
								hasMethod = true;
								String ns = m.getMethodParam().getInputName()
										+ "@"
										+ m.getMethodParam()
												.getInputNamespace();
								rh.setWebServicesInputParam(ns);
								ctx.setMethod(m);
								HashMap<String, String> qos = new HashMap<String, String>();
								for (Qos q : m.getQosList()) {
									qos.put(q.getName(), q.getValue());
								}
								ctx.setMethodQos(qos);
								break;

							}
						}
						if (!hasMethod) {
							throw new BasheException(
									BasheErrorCode.SERVICE_METHOD_ERROR,
									"service [" + rh.getServiceCode() + "]"
											+ "has no such method ["
											+ rh.getMethod() + "]");
						}
					} else {

						String s = rh.getWebServicesInputParam();
						List<WebServicesMethod> l = tmp.getVersion(version)
								.getBinding().getWebServicesBinding()
								.getWebServicesMethodList();
						for (WebServicesMethod m : l) {
							String ns = m.getMethodParam().getInputName() + "@"
									+ m.getMethodParam().getInputNamespace();
							if (ns.equals(s)) {
								hasMethod = true;
								ctx.setMethod(m);
								HashMap<String, String> qos = new HashMap<String, String>();
								for (Qos q : m.getQosList()) {
									qos.put(q.getName(), q.getValue());
								}
								ctx.setMethodQos(qos);
								break;
							}
						}
						if (!hasMethod) {
							throw new BasheException(
									BasheErrorCode.SERVICE_METHOD_ERROR,
									"service ["
											+ rh.getServiceCode()
											+ "]"
											+ "has no method's input param matching ["
											+ s + "]");
						}
					}

				}

			} else {
				MappingServiceInfoWrapper tmp = (MappingServiceInfoWrapper) ser;

				ctx.setMappingService(tmp);
			}

		} catch (Exception e) {
			logger.error("ServiceInfoQueryHandler.process() error", e);
			ctx.setError(e);
		}

	}

}
